use crate::error::{AppError, Result};
use crate::models::CrawlerConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tokio::fs;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub crawler: CrawlerConfig,
    pub basic_settings: BasicSettings,
    pub network_settings: NetworkSettings,
    pub storage_settings: StorageSettings,
    pub notification_settings: NotificationSettings,
    pub ui_settings: UiSettings,
    pub security_settings: SecuritySettings,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BasicSettings {
    pub max_concurrency: i32,
    pub request_delay: f64,
    pub timeout: i32,
    pub retry_count: i32,
    pub headless: bool,
    pub save_login_state: bool,
    pub auto_retry: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkSettings {
    pub enable_proxy: bool,
    pub proxy_host: String,
    pub proxy_port: i32,
    pub proxy_type: String,
    pub proxy_pool_size: i32,
    pub user_agent: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageSettings {
    pub default_storage: String,
    pub data_path: String,
    pub auto_backup: bool,
    pub backup_interval: String,
    pub auto_cleanup: bool,
    pub retention_days: i32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NotificationSettings {
    pub desktop: bool,
    pub task_complete: bool,
    pub error: bool,
    pub email: bool,
    pub email_address: String,
    pub smtp_server: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UiSettings {
    pub theme: String,
    pub language: String,
    pub font_size: i32,
    pub scale: i32,
    pub start_minimized: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecuritySettings {
    pub encryption: bool,
    pub require_password: bool,
    pub password: String,
    pub auto_lock: bool,
    pub lock_timeout: i32,
    pub log_access: bool,
    pub log_operations: bool,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            crawler: CrawlerConfig::default(),
            basic_settings: BasicSettings {
                max_concurrency: 3,
                request_delay: 2.0,
                timeout: 30,
                retry_count: 3,
                headless: false,
                save_login_state: true,
                auto_retry: false,
            },
            network_settings: NetworkSettings {
                enable_proxy: false,
                proxy_host: "127.0.0.1".to_string(),
                proxy_port: 7890,
                proxy_type: "http".to_string(),
                proxy_pool_size: 2,
                user_agent: String::new(),
            },
            storage_settings: StorageSettings {
                default_storage: "sqlite".to_string(),
                data_path: "./data".to_string(),
                auto_backup: true,
                backup_interval: "daily".to_string(),
                auto_cleanup: false,
                retention_days: 30,
            },
            notification_settings: NotificationSettings {
                desktop: true,
                task_complete: true,
                error: true,
                email: false,
                email_address: String::new(),
                smtp_server: String::new(),
            },
            ui_settings: UiSettings {
                theme: "light".to_string(),
                language: "zh-CN".to_string(),
                font_size: 14,
                scale: 100,
                start_minimized: false,
            },
            security_settings: SecuritySettings {
                encryption: false,
                require_password: false,
                password: String::new(),
                auto_lock: false,
                lock_timeout: 15,
                log_access: true,
                log_operations: true,
            },
        }
    }
}

impl AppConfig {
    pub fn config_path() -> Result<PathBuf> {
        let config_dir = dirs::config_dir()
            .ok_or_else(|| AppError::Config("Failed to get config directory".to_string()))?;
        
        let app_config_dir = config_dir.join("mediacrawler-gui");
        std::fs::create_dir_all(&app_config_dir)?;
        
        Ok(app_config_dir.join("config.json"))
    }

    pub async fn load() -> Result<Self> {
        let config_path = Self::config_path()?;
        
        if !config_path.exists() {
            let default_config = Self::default();
            default_config.save().await?;
            return Ok(default_config);
        }

        let content = fs::read_to_string(config_path).await?;
        let config: AppConfig = serde_json::from_str(&content)?;
        Ok(config)
    }

    pub async fn save(&self) -> Result<()> {
        let config_path = Self::config_path()?;
        let content = serde_json::to_string_pretty(self)?;
        fs::write(config_path, content).await?;
        Ok(())
    }

    pub async fn reset() -> Result<Self> {
        let default_config = Self::default();
        default_config.save().await?;
        Ok(default_config)
    }
}